test(scripts): batch 6b — assertion floors for nine scripts/** self-tests (sink repair + hoisted battery) - #15248
Merged
Conversation
…y roster `cases` with no failing entry was this self-test's only success condition, so "every case held" and "the cases never ran" printed the same line. Batch 6b of the roster-floor transplant, two shapes at once: - the sink repair PR #15156 landed: the concise arrow `const t = (name, ok, detail) => cases.push(...)` gains a block body and registers the case before recording it. `cases.push` receives exactly the arguments it always did -- no case is rewritten, reordered or re-judged. - the single hoisted battery PR #15217 landed: this file carries no named section banner, so it declares ONE battery opened at the top of the self-test body, floor at the measured count (12), and pins the roster's own size at 1. No comment is promoted to a section head. A breach files into the self-test's own `cases` sink, so the existing verdict reds on it with no verdict line rewritten; the #13798 handshake is untouched. Cases before == after: 12 == 12, measured on runs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
…attery roster `failed === 0` was this self-test's only success condition, so "every case held" and "the cases never ran" printed the same line. Batch 6b, two shapes at once: - the sink repair PR #15156 landed: the 12 inline `cases.push({...})` sites route through ONE block-bodied in-body helper, `addCase`, which registers the case and then performs the identical push. The case object is passed through untouched and the loop that runs the cases is not touched at all -- no case is rewritten, reordered or re-judged. - the single hoisted battery PR #15217 landed: this file carries no named section banner (its `--- n/m: ... ---` comments label fixtures, not sections), so it declares ONE battery opened at the top of the self-test body, floor at the measured count (12), roster size pinned at 1. No comment is promoted to a section head. A breach files into the self-test's own `failed` counter, so the existing verdict reds on it with no verdict line rewritten; the #13798 handshake is untouched. Normal mode stays green on the tree. Cases before == after: 12 == 12, measured on runs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
…tch6b-sink-plus-battery
baozhoutao
marked this pull request as ready for review
September 4, 2026 07:33
baozhoutao
enabled auto-merge
September 4, 2026 07:34
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #13799 (batch 6b — the class-1 + class-2 deferrals from PR #15003's table: sink repair plus a single hoisted battery).
Dispatched by PM claim
5536969005; dev claim5536991755. Branched atorigin/main=1bc3c092a, the dispatch pin, re-read and still matching at the branch point.origin/mainwas merged in at332ada04c(a real merge commit — no rebase, no force-push) after PR #15217 and three siblings landed; the merge touches neither of the two files this PR edits.2 of the 9 dispatched files are floored here. 7 are deferred with a measured reason rather than improvised, per the dispatch's own instruction to defer table-driven / bare-throw files to the loop-body decision. The deferral is the finding of this batch, and the evidence is below.
Floored (2)
scripts/check-pnpm-acquisition.mjsconst t = (name, ok, detail) => cases.push({...}), called at 12 per-case sitesregisterCase()then the identicalcases.push({ name, ok: Boolean(ok), detail })check-pnpm-acquisition self-testscripts/check-skill-frame-freshness.mjscases.push({...})written inline at 12 per-case sites, no helperaddCase(c):registerCase()thencases.push(c); the 12 sites call itcheck-skill-frame-freshness self-testBoth declare
SELF_TEST_BATTERY_FLOOR = 1(the roster's own size, so deleting the entry cannot silence the floor),UNATTRIBUTED_BATTERY, and a floor evaluated before the verdict that refuses a below-floor or DID-NOT-RUN battery and an undeclared one. Neither file carries two named section banners, so each declares ONE battery opened at the top of the self-test body — the PR #14896 / #15003 / #15217 hoisted shape. No comment is promoted to a section head. No assertion condition is inverted, rewritten, reordered or re-judged; the case objects are passed through untouched and the loop that runs them is not touched at all. A floor breach is filed into each file's own existing failure sink (caseswithok: false; thefailedcounter), so the existing verdict reds on it with no verdict line rewritten, and the #13798 handshake is byte-unchanged.Case count before == after, measured on runs
1bc3c092acheck-pnpm-acquisitioncheck-skill-frame-freshnessLine-level identity of the sink rewrite
Removed lines that do not reappear in the added lines after normalising indentation:
check-pnpm-acquisition— 1 residue,const t = (name, ok, detail) => cases.push({ name, ok: Boolean(ok), detail });. Fully explained: the concise arrow was split into head +registerCase();+ body, and its expression bodycases.push({ name, ok: Boolean(ok), detail });reappears verbatim inside the block body.check-skill-frame-freshness— 12 residues, all of them the opener linecases.push({rewritten toaddCase({. The case object literals that follow never enter the diff at all, which is the point: nothing about any case changed.Ablation (each leg proves its mutation landed on disk; each restore is proven by HEAD-blob hash equality, not by an exit code)
Both files are plain
node scripts/NAME.mjsentrypoints — executed from source, never resolved through a packageexportsinto adist/, so no rebuild leg applies and no stale-artefact false green is available here. Both ablations ran against a committed implementation, so the restore leg had a real reference point. The harness carriestrap ... EXIT INT TERMwith absolute paths.check-pnpm-acquisition, battery opener renamedbattery "check-pnpm-acquisition self-test" DID NOT RUN — 0 cases registered, 12 pinned, plus the undeclared-battery refusal;3 of 15 case(s) failed, so all 12 original cases still pass2f60872== HEAD blob,git diff HEADemptycheck-pnpm-acquisition,registerCase()removed from the helper2 of 14 case(s) failed, so all 12 original cases still pass2f60872== HEAD blob,git diff HEADemptycheck-skill-frame-freshness, battery opener renamedb9ff265== HEAD blob,git diff HEADemptycheck-skill-frame-freshness,registerCase()removed fromaddCaseb9ff265== HEAD blob,git diff HEADemptyOne ablation leg was rejected by its own landing check before it could produce a reading: the first
registerCase()-removal attempt passed an anchor with a trailing newline, sogrep -cread it as two patterns (the empty one matching every line) and reported685 -> 684. The run stopped, the trap restored the tree, and the leg was re-run with a corrected anchor. Recorded because the first attempt produced no measurement, not a passing one.extractWatchHintson both trees, per fileRun through the real
extractWatchHintsexported byscripts/pm/dispatch-gates.mjs(untouched by this PR), on the pin's content and this branch's content:1bc3c092acheck-pnpm-acquisition.mjs[".github/workflows"][".github/workflows"]check-skill-frame-freshness.mjs[][]check:watch-hint-literalgreen: 49 declarations across 4 rostered names.The card's instrument, with the concurrent batch accounted for rather than asserted
node scripts/measure-self-test-floor.mjs --json, at the pin and on this branch:1bc3c092aNONEROSTER11 files moved
NONEtoROSTERacross that range. 9 are PR #15217 (batch 5), which merged in between and is in this branch through the merge commit; 2 are this PR's. Unexplained movement: none. Symmetric difference of (moved, minus batch 5's nine) against this batch's floored worklist: empty. So theNONEdrop attributable to this PR is exactly 2, the number floored.All 7 deferred files read exactly as they did at the pin — six
NONE, oneCOUNT— i.e. untouched.Deferred (7), each with the measurement that decided it
⛔ Not improvised. The dispatch reserves table-driven and bare-throw files for the loop-body decision, and all seven measure as the same shape: a literal
const cases = [ ... ]table, zerocases.pushsites, exactly one loop over the table, and sink writes that are failure-only.1bc3c092acheck-refd-timer-probe.mjsfailedsink at 5 inline sites; 0 bannerscontinuecontinuecheck-sdui-manifest.mjsfailuressink at 1 inline site; 0 bannerscheck-skill-compatibility-version.mjsfailedsink at 7 inline sites; 1 bannercontinuecontinuecheck-skill-frame-sync.mjsfailedsink at 5 inline sites; 1 bannercontinuecontinuecheck-skills-token-ratchet.mjsfailedsink at 1 inline site; 0 bannerscheck-widget-option-census.mjsfailedsink at 5 inline sites; 1 bannercontinuechecksdriven by a second looppm/check-skill-id-lint.mjsfailedsink at 1 inline site; 0 bannersWhy the recipe cannot be applied to these without the reserved decision. PR #15003's table counts the
failed += 1/failures++sites as "inline sites", but every one of them is lexically inside a failure branch or acatch— verified on all seven, guard by guard. So routing them through a block-bodied helper that callsregisterCase()would register a case only when a case fails: a fully green run would register zero cases and the battery would read DID NOT RUN. That is the floor inverted, not installed — the one outcome this card exists to prevent. There is no per-case sink to repair, and the only site that executes once per case regardless of outcome is the loop body itself, which is exactly the loop-body decision the dispatch reserved. Batch 4's thunk is not an escape either: in 4 of the 7 the loop body carriescontinue, which cannot cross a function boundary, socheck(() => { ... })cannot wrap those bodies verbatim.This matches the card's own Tier C wording — "table-driven self-tests where the natural roster is the table's own named rows rather than sections" — so the natural remedy for these seven is a roster of the table's named rows, which is a shape no batch has landed yet.
One re-verification correction to carry forward:
check-refd-timer-probe.mjsreadsCOUNT, notNONE, on the instrument — it is one of the two files on the tree that derive and print a case count nothing compares (the other ispm/check-half-states.mjs, excluded by the dispatch). The card body names a different pair, which the two intervening batches have since moved.Verification
Exit codes captured by redirect before any pipe; every result below is the gate's own printed verdict line, never a bare status variable. All runs in the foreground, on final commit
332ada04c(git rev-parse --short HEADfrom the same tree the runs used).Derived family —
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, which derives its own change set from the merge base (no hand-passed path list). The first derivation refused to be trusted, printing STALE TREE and namingcheck-ratchet-remedy-authority.mjsanddispatch-gates.mjsas changed under it;origin/mainwas fetched and merged and the family re-derived clean. 23 commands, all exit 0.Always-runs tail:
check:pm-dispatch-gates(1353 cases pass) ·check:self-test-wired(168 scripts, every one CI runs) ·check-self-test-workflow-commandsand its--self-test·check:declared-population-live(201 of 252 families reach this tree's 8281 files) ·check:ratchet-remedy-authority(202 scripts swept) ·check:watch-hint-literal·check:nul-bytes(8274 files scanned, no raw control bytes). All exit 0.Each edited script's own suite, normal mode against the tree and
--self-test, all exit 0 — both arelint.ymlgates and both stay green on the tree:check-pnpm-acquisitionnormal +--self-test(12 cases pass)check-skill-frame-freshnessnormal +--self-test(12 cases pass); normal mode reports the decision frame current withorigin/main, 2 copies across 2 filesNeither script is named by any test file in the tree (
git grepover test globs: no hits; referenced only from.github/workflows/lint.ymlandpackage.json), so no separate suite is owed.Control-byte scan of both edited files and of every body posted to GitHub: clean.
skip-changeset: this PR publishes nothing from any package — it edits twoscripts/**gate self-tests. Label applied through the additive endpoint and read back.Generated by Claude Code